package com.ruoyi.framework.interceptor;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import cn.hutool.core.io.FileUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.SecurityUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.MDC;
import org.slf4j.spi.MDCAdapter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.ServletUtils;

/**
 * 防止重复提交拦截器
 */
@Component
public abstract class RepeatSubmitInterceptor implements HandlerInterceptor
{

    private Log logger = LogFactory.getLog(RepeatSubmitInterceptor.class);
    private static List<File> javaFiles = new ArrayList<File>();

    public static boolean isDebugLog = true;
    private Log log = LogFactory.getLog(RepeatSubmitInterceptor.class);
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
    {
        if (handler instanceof HandlerMethod)
        {
            HandlerMethod handlerMethod = (HandlerMethod) handler;

            Method method = handlerMethod.getMethod();
            RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
            if (annotation != null)
            {
                if (this.isRepeatSubmit(request, annotation))
                {
                    AjaxResult ajaxResult = AjaxResult.error(annotation.message());
                    ServletUtils.renderString(response, JSON.toJSONString(ajaxResult));
                    return false;
                }
            }
            logRequest(request,handlerMethod);
            debugLog( request,  handlerMethod, "");
            return true;
        }
        else
        {
            return true;
        }
    }

    private void logRequest(HttpServletRequest request,HandlerMethod handlerMethod) {
        Method method = handlerMethod.getMethod();
        String url = request.getRequestURI();
        SysUser user = null;
        try {
            user = SecurityUtils.getLoginUser().getUser();
        }catch (Exception e) {

        }
        Annotation[] classAnnotations = handlerMethod.getBeanType().getAnnotations();
        String className = "";
        for(Annotation annotation : classAnnotations){
            if(annotation instanceof RestController){
                RestController mapping = (RestController)annotation;
                className = mapping.value();
            }
        }
        Annotation[] annotations = method.getAnnotations();
        String methodName = null;
        for(Annotation annotation : annotations){
            if(annotation instanceof GetMapping){
                GetMapping mapping = (GetMapping)annotation;
                methodName = mapping.name();
            }else if(annotation.getClass().equals(PostMapping.class)){
                PostMapping mapping = (PostMapping)annotation;
                methodName = mapping.name();
            }else if(annotation.getClass().equals(DeleteMapping.class)){
                DeleteMapping mapping = (DeleteMapping)annotation;
                methodName = mapping.name();
            }else if(annotation.getClass().equals(PutMapping.class)){
                PutMapping mapping = (PutMapping)annotation;
                methodName = mapping.name();
            }
        }
        if(StrUtil.isBlank(methodName)){
            methodName = method.getName();
        }
        if(user != null){
            String menu = (className + "/" + methodName).replaceAll("/+","/");
            log.debug(StrUtil.format("用户：{}   功能：{}  url：{}" , user.getNickName() , menu , url));
        }
    }

    /**
     * 验证是否重复提交由子类实现具体的防重复提交的规则
     *
     * @param request
     * @return
     * @throws Exception
     */
    public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation);


    private void debugLog(HttpServletRequest request, HandlerMethod method, String prefix){

        Throwable t = new Throwable();
        t.fillInStackTrace();
        StackTraceElement[] stackTrace = t.getStackTrace();

        String projectDir = "D:\\git-projects\\small_enterprise_it_platform\\3开发阶段\\代码\\small_enterprise_it_platform";
        if(isDebugLog && !new File(projectDir).exists()){
            isDebugLog = false;
        }
        if(!isDebugLog){
            RequestMapping requestMapping = method.getMethodAnnotation(RequestMapping.class);
            logger.info("访问结束：" + (requestMapping!=null ? requestMapping.name() +" ":" ") +  request.getRequestURI());
            return;
        }
        if(javaFiles.size() == 0){
            javaFiles = FileUtil.loopFiles(projectDir, new FileFilter() {
                @Override
                public boolean accept(File file) {
                    if(file.getName().endsWith(".java")){
                        return true;
                    }
                    return false;
                }
            });
        }

        Class controllerType = method.getResolvedFromHandlerMethod().getBeanType();
        String javaPath = controllerType.getName().replaceAll("\\.","\\\\") + ".java";
        File javaFile = javaFiles.stream().filter(file -> file.getAbsolutePath().contains(javaPath)).findAny().orElse(null);
        StringBuilder dump = new StringBuilder();
        try {
            RequestMapping requestMapping = method.getMethodAnnotation(RequestMapping.class);
            List<String> lines = FileUtil.readLines(javaFile,"utf-8");
            for(int i=0;i<lines.size();i++){
                String line = lines.get(i);
                dump.setLength(0);
                String fileName = controllerType.getSimpleName()+".java";
                String methodTitle = requestMapping!=null ? requestMapping.name() :" ";
                String className = method.getMethod().getDeclaringClass().getSimpleName();
                int lineNumber = i+1;
                dump.append(prefix).append(methodTitle)
                        .append(className).append(".").append(method.getMethod().getName()).append("(").
                        append(fileName).append(":").append(lineNumber).append(")");

                if(line.contains(" " + method.getMethod().getName()) && (line.contains("{") || (i > 0 && lines.get(i-1).contains("RequestMapping")))){
                    logger.info(dump.toString());
                    break;
                }
            }
        } catch (Exception e) {
            logger.info(controllerType.getSimpleName()+"，方法名："+method.getMethod().getName());
        }
    }
}
